package com.tools.web.filter.gateway;

import com.tools.common.object.Note;
import com.tools.common.thread.TimePair;
import com.tools.common.thread.Timeunit;
import com.tools.middle.redis.client.JedisPlus;
import com.tools.web.WebKit;
import com.tools.web.interceptor.auth.AuthenticationManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import redis.clients.jedis.Jedis;

import java.util.Objects;
import java.util.Set;

/**
 * 使用 JedisPlus 客户端操作单机 Redis 实现的网关过滤器
 * */
@Note("使用 JedisPlus 客户端操作单机 Redis 实现的网关过滤器")
public final class JedisPlusGatewayManager extends AbsGatewayManager implements GatewayRedisLuaScript {
    
    @Note("操作单机 Redis 的客户端实例")
    private final JedisPlus jedisPlus;

    @Note("是否禁用所有的 REST 接口")
    private boolean disabledAllRestApi = false;

    private static final Logger LOGGER = LoggerFactory.getLogger(JedisPlusGatewayManager.class);

    /* ********************************************************************************************
     *
     *         构造器
     *
     * *********************************************************************************************
     * */
    
    public JedisPlusGatewayManager(JedisPlus jedisPlus, GatewaySource source) {
        this(jedisPlus, source, null);
    }

    public JedisPlusGatewayManager(JedisPlus jedisPlus, GatewaySource source, AuthenticationManager authenticationManager) {
        super(source, authenticationManager);
        this.jedisPlus = Objects.requireNonNull(jedisPlus);
    }

    /* ********************************************************************************************
     *
     *         实现的方法
     *
     * *********************************************************************************************
     * */

    @Override
    protected Logger protected_getLogger() {
        return LOGGER;
    }

    @Override
    protected long protected_toSubclassDomainUnitTime(TimePair addBlackerThresholdTime) {
        return Timeunit.toSecond(addBlackerThresholdTime);
    }

    @Override
    protected String protected_checkIfAddIPInBlacksAndGetTimeunitLabel(String clientIP) {
        try {
            String key = super.protected_getAddBlackSaveKey(clientIP);
            long addBlackerThresholdTime = super.getAddBlackerThresholdTime();
            int addBlackerThreshold = super.getAddBlackerThreshold();
            Integer result = (Integer) this.jedisPlus.eval(HAS, 1, key, addBlackerThresholdTime, addBlackerThreshold);
            if(result != null && result == 1) return null;
            super.addInIpBlacks(clientIP);
            this.jedisPlus.del(key);
            return Timeunit.SECOND.getText();
        } finally {
            this.jedisPlus.close();
        }
    }

    @Override
    protected void protected_setDisabledAllURIProperty(boolean all) {
        this.disabledAllRestApi = all;
    }

    @Override
    protected int protected_initDisabledURIs(Set<String> disabledURIs) {
        if(disabledURIs == null || disabledURIs.isEmpty()) return 0;
        try {
            return (int) this.jedisPlus.sadd(super.getDisableURICacheKey(), disabledURIs);
        } finally {
            this.jedisPlus.close();
        }
    }

    @Override
    protected boolean protected_isInDisabledURIs(String uri) {
        try {
            return this.jedisPlus.sismember(super.getDisableURICacheKey(), uri);
        } finally {
            this.jedisPlus.close();
        }
    }

    @Override
    public JedisPlusGatewayManager addInDisabledURIs(String uri) {
        try {
            if(this.enabledDisabledURIs()) {
                if("*".equals(uri)) this.disabledAllRestApi = true;
                else this.jedisPlus.jedis().sadd(super.getDisableURICacheKey(),
                        WebKit.uriAddServerContextPath(uri, super.getServerContextPath()));
            }
            return this;
        } finally {
            this.jedisPlus.close();
        }
    }

    @Override
    public JedisPlusGatewayManager addAllInDisabledURIs(String... uris) {
        try {
            if(this.enabledDisabledURIs()) {
                String[] newURIs = super.protected_checkAsNewURISet(uris, true);
                if(newURIs != null) this.jedisPlus.jedis().sadd(super.getDisableURICacheKey(), newURIs);
            }
            return this;
        } finally {
            this.jedisPlus.close();
        }
    }

    @Override
    public JedisPlusGatewayManager addAllInDisabledURIs(Iterable<String> uris) {
        try {
            if(this.enabledDisabledURIs()) {
                String[] newURIs = super.protected_checkAsNewURISet(uris, true);
                if(newURIs == null) return this;
                this.jedisPlus.jedis().sadd(super.getDisableURICacheKey(), newURIs);
            }
            return this;
        } finally {
            this.jedisPlus.close();
        }
    }

    @Override
    public JedisPlusGatewayManager removeFromDisabledURIs(String uri) {
        try {
            if(this.enabledDisabledURIs()) {
                if("*".equals(uri)) this.disabledAllRestApi = false;
                else this.jedisPlus.jedis().srem(super.getDisableURICacheKey(),
                        WebKit.uriAddServerContextPath(uri, super.getServerContextPath()));
            }
            return this;
        } finally {
            this.jedisPlus.close();
        }
    }

    @Override
    public JedisPlusGatewayManager removeAllFromDisabledURIs(String... uris) {
        try {
            if(this.enabledDisabledURIs()) {
                String[] newURIs = super.protected_checkAsNewURISet(uris, false);
                if(newURIs != null) this.jedisPlus.jedis().srem(super.getDisableURICacheKey(), newURIs);
            }
            return this;
        } finally {
            this.jedisPlus.close();
        }
    }

    @Override
    public JedisPlusGatewayManager removeAllFromDisabledURIs(Iterable<String> uris) {
        try {
            if(this.enabledDisabledURIs()) {
                String[] newURIs = super.protected_checkAsNewURISet(uris, false);
                if(newURIs == null) return this;
                this.jedisPlus.jedis().srem(super.getDisableURICacheKey(), newURIs);
            }
            return this;
        } finally {
            this.jedisPlus.close();
        }
    }

    @Override
    public JedisPlusGatewayManager clearDisabledURIs() {
        try {
            if(this.enabledDisabledURIs()) {
                this.jedisPlus.jedis().del(super.getDisableURICacheKey());
            }
            return this;
        } finally {
            this.jedisPlus.close();
        }
    }

    @Override
    public boolean isInDisabledURIs(String uri) {
        try {
            if(this.enabledDisabledURIs()) {
                if(this.disabledAllRestApi) return true;
                return this.jedisPlus.jedis().sismember(super.getDisableURICacheKey(),
                        WebKit.uriAddServerContextPath(uri, super.getServerContextPath()));
            }
            return false;
        } finally {
            this.jedisPlus.close();
        }
    }

    @Override
    public boolean isAllInDisabledURIs(String... uris) {
        try {
            if(this.enabledDisabledURIs()) {
                if(this.disabledAllRestApi) return true;
                String[] newURIs = super.protected_checkAsNewURISet(uris, null);
                if(newURIs == null) return false;
                String disableURICacheKey = super.getDisableURICacheKey();
                Jedis jedis = this.jedisPlus.jedis();
                for(String uri : newURIs) {
                    if(!jedis.sismember(disableURICacheKey, uri)) return false;
                }
                return true;
            }
            return false;
        } finally {
            this.jedisPlus.close();
        }
    }

    @Override
    public boolean isAllInDisabledURIs(Iterable<String> uris) {
        try {
            if(this.enabledDisabledURIs()) {
                if(this.disabledAllRestApi) return true;
                String[] newURIs = super.protected_checkAsNewURISet(uris, null);
                if(newURIs != null) {
                    String disableURICacheKey = super.getDisableURICacheKey();
                    Jedis jedis = this.jedisPlus.jedis();
                    for(String uri : newURIs) {
                        if(!jedis.sismember(disableURICacheKey, uri)) return false;
                    }
                    return true;
                }
                return false;
            }
            return false;
        } finally {
            this.jedisPlus.close();
        }
    }

    @Override
    public boolean isAnyInDisabledURIs(String... uris) {
        try {
            if(this.enabledDisabledURIs()) {
                if(this.disabledAllRestApi) return true;
                String[] newURIs = super.protected_checkAsNewURISet(uris, null);
                if(newURIs == null) return false;
                String disableURICacheKey = super.getDisableURICacheKey();
                for(String uri : newURIs) {
                    if(this.jedisPlus.sismember(disableURICacheKey, uri)) return true;
                }
            }
            return false;
        } finally {
            this.jedisPlus.close();
        }
    }

    @Override
    public boolean isAnyInDisabledURIs(Iterable<String> uris) {
        try {
            if(this.enabledDisabledURIs()) {
                if(this.disabledAllRestApi) return true;
                String[] newURIs = super.protected_checkAsNewURISet(uris, null);
                if(newURIs != null) {
                    String disableURICacheKey = super.getDisableURICacheKey();
                    for(String uri : newURIs) {
                        if(this.jedisPlus.sismember(disableURICacheKey, uri)) return true;
                    }
                }
                return false;
            }
            return false;
        } finally {
            this.jedisPlus.close();
        }
    }

    /* ********************************************************************************************
     *
     *         重写的方法
     *
     * *********************************************************************************************
     * */

    @Override
    public JedisPlusGatewayManager addInProxyWhites(String remote) {
        super.addInProxyWhites(remote);
        return this;
    }

    @Override
    public JedisPlusGatewayManager addAllInProxyWhites(String... remotes) {
        super.addAllInProxyWhites(remotes);
        return this;
    }

    @Override
    public JedisPlusGatewayManager addAllInProxyWhites(Iterable<String> remotes) {
        super.addAllInProxyWhites(remotes);
        return this;
    }

    @Override
    public JedisPlusGatewayManager removeFromProxyWhites(String remote) {
        super.removeFromProxyWhites(remote);
        return this;
    }

    @Override
    public JedisPlusGatewayManager removeAllFromProxyWhites(String... remotes) {
        super.removeAllFromProxyWhites(remotes);
        return this;
    }

    @Override
    public JedisPlusGatewayManager removeAllFromProxyWhites(Iterable<String> remotes) {
        super.removeAllFromProxyWhites(remotes);
        return this;
    }

    @Override
    public JedisPlusGatewayManager clearProxyWhites() {
        super.clearProxyWhites();
        return this;
    }

    @Override
    public JedisPlusGatewayManager addInIpWhites(String clientIP) {
        super.addInIpWhites(clientIP);
        return this;
    }

    @Override
    public JedisPlusGatewayManager addAllInIpWhites(String... clientIPs) {
        super.addAllInIpWhites(clientIPs);
        return this;
    }

    @Override
    public JedisPlusGatewayManager addAllInIpWhites(Iterable<String> clientIPs) {
        super.addAllInIpWhites(clientIPs);
        return this;
    }

    @Override
    public JedisPlusGatewayManager removeFromIpWhites(String clientIP) {
        super.removeFromIpWhites(clientIP);
        return this;
    }

    @Override
    public JedisPlusGatewayManager removeAllFromIpWhites(String... clientIPs) {
        super.removeAllFromIpWhites(clientIPs);
        return this;
    }

    @Override
    public JedisPlusGatewayManager removeAllFromIpWhites(Iterable<String> clientIPs) {
        super.removeAllFromIpWhites(clientIPs);
        return this;
    }

    @Override
    public JedisPlusGatewayManager clearIpWhites() {
        super.clearIpWhites();
        return this;
    }

    @Override
    public JedisPlusGatewayManager addInIpBlacks(String clientIP) {
        super.addInIpBlacks(clientIP);
        return this;
    }

    @Override
    public JedisPlusGatewayManager addInIpBlacks(String... clientIPs) {
        super.addInIpBlacks(clientIPs);
        return this;
    }

    @Override
    public JedisPlusGatewayManager addInIpBlacks(Iterable<String> clientIPs) {
        super.addInIpBlacks(clientIPs);
        return this;
    }

    @Override
    public JedisPlusGatewayManager removeFromIpBlacks(String clientIP) {
        super.removeFromIpBlacks(clientIP);
        return this;
    }

    @Override
    public JedisPlusGatewayManager removeAllFromIpBlacks(String... clientIPs) {
        super.removeAllFromIpBlacks(clientIPs);
        return this;
    }

    @Override
    public JedisPlusGatewayManager removeAllFromIpBlacks(Iterable<String> clientIPs) {
        super.removeAllFromIpBlacks(clientIPs);
        return this;
    }

    @Override
    public JedisPlusGatewayManager clearIpBlacks() {
        super.clearIpBlacks();
        return this;
    }
}
